package com.yygo.webapp.controller.loanrequest;

import com.yygo.Constants;
import com.yygo.configentity.action.Action;
import com.yygo.model.*;
import com.yygo.model.enums.*;
import com.yygo.service.CityManager;
import com.yygo.service.CountyManager;
import com.yygo.service.LoanProductManager;
import com.yygo.service.ProvinceManager;
import com.yygo.util.DateUtil;
import com.yygo.util.IdCardValidator;
import com.yygo.util.MobileFromUtil;
import com.yygo.util.StringUtil;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.appfuse.service.GenericManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ExtendedModelMap;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.security.Principal;
import java.text.SimpleDateFormat;
import java.util.*;

//import org.springframework.mobile.device.Device;
//import org.springframework.mobile.device.DeviceUtils;

@Controller
@RequestMapping("/loanRequestform*")
public class LoanRequestFormController extends BaseLoanRequestFormController {

    @Autowired
    private ProvinceManager provinceManager;
    @Autowired
    private CityManager cityManager;

    @Autowired
    private CountyManager countyManager;

    @Autowired
    private GenericManager<TalkRecord, Long> talkRecordManager;
    @Autowired
    private GenericManager<Attachment, Long> attachmentManager;

    @Autowired
    private LoanProductManager loanProductManager;

    public LoanRequestFormController() {
        setCancelView("redirect:loanRequests");
        setSuccessView("redirect:loanRequests");
    }

    @Override
    @InitBinder
    protected void initBinder(final HttpServletRequest request, final ServletRequestDataBinder binder) {
        super.initBinder(request, binder);
        binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("MM/dd/yyyy"), true));
    }

    private void checkAuthority(User loginUser, LoanRequest loanRequest) {
        boolean isDealer = loginUser.hasRole(Constants.DEALER_USER_ROLE);
        boolean isBankUser = loginUser.hasRole(Constants.Bank_USER_ROLE) ||
                loginUser.hasRole(Constants.Material_Receive_ROLE) ||
                loginUser.hasRole(Constants.Material_Audit_ROLE) ||
                loginUser.hasRole(Constants.Material_Print_ROLE) ||
                loginUser.hasRole(Constants.Bank_CREDIT_ROLE);
        boolean isBondUser = loginUser.hasRole(Constants.Bond_USER_ROLE);
        if ((isDealer && !loanRequest.getDealerUser().equals(loginUser))
                || (isBankUser&& !bankManager.getUsers(loanRequest.getLoanProduct().getBank().getId()).contains(loginUser))
                || (isBondUser && !(loanRequest.getDealer().getBond().getBondUser().equals(loginUser)
                || loanRequest.getDealer().getSlaveProvider().getBondUser().equals(loginUser) || loanRequest.getDealer().getMasterProvider().getBondUser().equals(loginUser)))) {
            throw new AccessDeniedException("You do not have permission to view/edit other loan request.");
        } else if (!isDealer && !isBankUser && !isBondUser && (loanRequest.getPhase().equals(Phase.draft) || loanRequest.getPhase().equals(Phase.dealer_submit))) {
            throw new AccessDeniedException("You do not have permission to view/edit other loan request.");
        }
    }

    @RequestMapping(method = RequestMethod.GET)
    protected ModelAndView showForm(HttpServletRequest request, Principal principal)
            throws Exception {
        String id = request.getParameter("reqId");
        String mode = request.getParameter("mode");
        User loginUser = userManager.getUserByUsername(principal.getName());

        // check if dealer can submit request
        if (loginUser.getDealer() != null && !loginUser.getDealer().isRequestEnabled()) {
            throw new AccessDeniedException("You do not have permission to submit loan request.");
        }
        Model model = new ExtendedModelMap();
        LoanRequest loanRequest;
        if (!StringUtils.isBlank(id)) {
            loanRequest = loanRequestManager.loadWholeLoanRequest(new Long(id));
            checkAuthority(loginUser, loanRequest);
            Collections.sort(loanRequest.getActivities(), new Comparator<Activity>() {
                @Override
                public int compare(Activity o1, Activity o2) {
                    return o1.getTime().before(o2.getTime()) ? 1 : -1;
                }
            });
            if (loanRequest.getLoanProduct() != null) {
                loanRequest.setLoanProductId(loanRequest.getLoanProduct().getId());
            }
            if (loanRequest.getCoPerson() != null && loanRequest.getCoPerson().getId() != null) {
                loanRequest.setCoLoaned(true);
            }
            if (loanRequest.getDbPerson() != null && loanRequest.getDbPerson().getId() != null) {
                loanRequest.setGuaranted(true);
            }
            if (loanRequest.getRequestPerson()!=null && loanRequest.getRequestPerson().getAddress()!=null ){
                if(loanRequest.getAddressCert()!=null && loanRequest.getAddressCert().equals(getText("MATERIAL_M35", request.getLocale()))){
                    model.addAttribute("showRate", true);
                }
            }
        } else {
            loanRequest = new LoanRequest();
            loanRequest.setNumber(getRequestNumber());
            loanRequest.setCoPerson(new LoanPerson());
            loanRequest.setDbPerson(new LoanPerson());
            Dealer dealer = loginUser.getDealer();
            loanRequest.setDealer(dealer);
            loanRequest.setDealerUser(loginUser);
            loanRequest.setAuditUser(null);
            //loanRequest.setFeedbackType(FeedbackStatus.None);
            loanRequest.setStatus(RequestStatus.draft);
            loanRequest.setPhase(Phase.draft);
            loanRequest.setRequestDate(new Date());
            loanRequest.setCoPerson(new LoanPerson());
            loanRequest.setDbPerson(new LoanPerson());
        }

        String view = "loanRequestform";
        /*Device currentDevice = DeviceUtils.getCurrentDevice(request);
        if (currentDevice.isMobile() || currentDevice.isTablet()) {
            view = "loanRequestformMobile";
        }*/

        com.yygo.configentity.action.Phase rolePhase = getRolePhase(loanRequest, loginUser);
        model.addAttribute("phaseInfo", rolePhase);

        String phaseStr = loanRequest.getPhase().toString();
        com.yygo.configentity.view.RoleView roleView = null;
        if (rolePhase != null) {
            roleView = roleViewsConfigurer.getPhase(rolePhase.getRole(), phaseStr);
        } else {
            for (Role role : loginUser.getRoles()) {
                roleView = roleViewsConfigurer.getPhase(role.getName(), phaseStr);
                if (rolePhase != null) {
                    break;
                }
            }
        }

        model.addAttribute("viewInfo", roleView);
        model.addAttribute("feedbackInfo", getRoleFeedback(loanRequest, loginUser));

        model.addAttribute("attachmentInfo", getAttachmentInfo(loanRequest, loginUser));

        view = roleView.getView();

        /*if (loginUser.hasRole(Constants.CC_ROLE) || loginUser.hasRole(Constants.CA_ROLE) || loginUser.hasRole(Constants.SCA_ROLE) || loginUser.hasRole(Constants.Booking_ROLE)
                || loginUser.hasRole(Constants.Bond_USER_ROLE) || loginUser.hasRole(Constants.Insurance_ROLE) || loginUser.hasRole(Constants.ADMIN_ROLE) || loginUser.hasRole(Constants.Bank_USER_ROLE)) {
            view = "loanRequestAuditform";
        }
        if (loanRequest.getPhase().equals(Phase.draft) || loanRequest.getPhase().equals(Phase.bank_credit_audit) || loanRequest.getStatus().equals(RequestStatus.credit_denied)
                || (loginUser.hasRole(Constants.Bank_CREDIT_ROLE) && loanRequest.getPhase().equals(Phase.dealer_submit))) {
            view = "loanRequestInit";
        }

        if (loginUser.hasRole(Constants.Bank_RECEIVER_ROLE)) {
            view = "loanRequestAuditform";
        }*/

        if (mode != null) {
            //edit mode for ca and sca
            if ((loginUser.hasRole(Constants.CA_ROLE) || loginUser.hasRole(Constants.SCA_ROLE)) && mode.equals("edit") && loginUser.getUsername().equals(loanRequest.getAuditUser().getUsername())) {
                view = "loanRequestform";
            }
        }

        model.addAttribute("loanRequest", loanRequest);
        return new ModelAndView(view, model.asMap());
    }

    double calculateMonthPay(float loanRate, float feeRate, float costRate, float loanAmount, int loanYears) {
        double month = 0;
        loanRate = loanRate / 100;
        feeRate = feeRate / 100;
        costRate = costRate / 100;
        int loanMonth = loanYears * 12;
        if (loanRate == 0 && feeRate > 0) {
            //month = Math.round(loanAmount*(1+feeRate)/loanMonth*100)/100;
            month = Math.round(loanAmount * (1 + feeRate - costRate) * (1 + costRate) / loanMonth * 100) / 100; //月供计算公式： 车价*（1-首付比例) * (1+手续费率-成本费率）*(1+成本费率）/贷款年限
        } else if (loanRate > 0) {
            loanAmount = loanAmount * (1 + feeRate);
            month = loanAmount * loanRate * Math.pow((1 + loanRate), loanMonth) / (Math.pow((1 + loanRate), loanMonth) - 1);
        }
        return month;
    }


    @RequestMapping(method = RequestMethod.POST)
    public String onSubmit(LoanRequest loanRequest, @RequestParam(required = false, value = "selectedIds") Long[] selectedIds, BindingResult errors, HttpServletRequest request,
                           HttpServletResponse response, Principal principal)
            throws Exception {
        boolean isNew = (loanRequest.getId() == null);
        if (isNew && request.getParameter("cancelRequest") != null) {
            return getCancelView();
        }

        String success = getSuccessView();
        Locale locale = request.getLocale();

        User loginUser = userManager.getUserByUsername(principal.getName());


        if (isNew) {
            Dealer dealer = loginUser.getDealer();
            loanRequest.setDealer(dealer);
            loanRequest.setDealerUser(loginUser);
            loanRequest.setAuditUser(null);
            //loanRequest.setFeedbackType(FeedbackStatus.None);
            loanRequest.setStatus(RequestStatus.draft);
            loanRequest.setPhase(Phase.draft);
            loanRequest.setRequestDate(new Date());
            MaterialAudit materialAudit = new MaterialAudit();
            materialAudit.setLoanRequest(loanRequest);
            loanRequest.setMaterialAudit(materialAudit);

        } else {
            LoanRequest oldRequest = loanRequestManager.loadWholeLoanRequest(loanRequest.getId());
            if ((request.getParameter("save") != null && !oldRequest.getPhase().equals(Phase.dealer_apply_loan))
                    || request.getParameter(ACTION_submitDraft) != null
                    || request.getParameter(ACTION_submitRequest) != null
                    || request.getParameter("saveAndUpload") != null) {
                restoreUnchanged(loanRequest, oldRequest);
                if (loanRequest.getPhase().equals(Phase.bank_credit_audit)) {
                    loanRequest.setRequestPerson(oldRequest.getRequestPerson());
                    if(oldRequest.isCoLoaned()){
                        loanRequest.setCoLoaned(oldRequest.isCoLoaned());
                        loanRequest.setCoPerson(oldRequest.getCoPerson());
                    }
                    if(oldRequest.isGuaranted()){
                        loanRequest.setGuaranted(oldRequest.isGuaranted());
                        loanRequest.setDbPerson(oldRequest.getDbPerson());
                    }
                    loanRequest.setLoanProduct(oldRequest.getLoanProduct());
                    loanRequest.setLoanProductId(oldRequest.getLoanProductId());
                    loanRequest.setSecond(oldRequest.isSecond());
                } else {
                    loanRequest.setRequestPersonCreditQuestionnaire(oldRequest.getRequestPersonCreditQuestionnaire());
                    loanRequest.setCoPersonCreditQuestionnaire(oldRequest.getCoPersonCreditQuestionnaire());
                    loanRequest.setDbPersonCreditQuestionnaire(oldRequest.getDbPersonCreditQuestionnaire());
                }
            } else {
                if (request.getParameter(ACTION_bankCreditDeny) != null || request.getParameter(ACTION_bankCreditApprove) != null
                        || request.getParameter(ACTION_bankGotoCA) != null) {
                    oldRequest.setRequestPersonCreditQuestionnaire(loanRequest.getRequestPersonCreditQuestionnaire());
                    oldRequest.setCoPersonCreditQuestionnaire(loanRequest.getCoPersonCreditQuestionnaire());
                    oldRequest.setDbPersonCreditQuestionnaire(loanRequest.getDbPersonCreditQuestionnaire());
                } else if (request.getParameter(ACTION_ccApprove) != null) { // cc pboc
                    TalkRecord talkRecord = new TalkRecord();
                    talkRecord.setOperator(loginUser.getUsername());
                    talkRecord.setTime(new Date());
                    talkRecord.setContent(loanRequest.getPbocComment());
                    oldRequest.getTalkRecordList().add(talkRecord);
                    oldRequest.setPbocComment(loanRequest.getPbocComment());
                } else if (request.getParameter(ACTION_caApprove) != null || request.getParameter(ACTION_scaApprove) != null || request.getParameter(ACTION_caSaveCredit)!=null) {
                    oldRequest.setAuditCode(loanRequest.getAuditCode());
                    oldRequest.setAddressCert(loanRequest.getAddressCert());
                    oldRequest.setIncomeCert(loanRequest.getIncomeCert());
                    oldRequest.setDriveCert(loanRequest.getDriveCert());
                    oldRequest.setIdentityCert(loanRequest.getIdentityCert());
                    oldRequest.setPropertyArea(loanRequest.getPropertyArea());
                    oldRequest.setPropertyGuarented(loanRequest.isPropertyGuarented());
                    oldRequest.setPricePerSquare(loanRequest.getPricePerSquare());
                    oldRequest.setCreditScore(loanRequest.getCreditScore());
                    oldRequest.setCreditScoreType(loanRequest.getCreditScoreType());
                    oldRequest.setXishu(loanRequest.getXishu());
                    oldRequest.setBasicPrice(loanRequest.getBasicPrice());
                    oldRequest.setAnnualMustCost(loanRequest.getAnnualMustCost());
                } else if ((request.getParameter(ACTION_applyLoan) != null)||
                        (request.getParameter("save") != null && oldRequest.getPhase().equals(Phase.dealer_apply_loan))) {
                    oldRequest.setVehicleManufactureDate(loanRequest.getVehicleManufactureDate());
                    oldRequest.setVehiclePurchaseDate(loanRequest.getVehiclePurchaseDate());
                    oldRequest.setFrameNo(loanRequest.getFrameNo());
                    oldRequest.setEngineNumber(loanRequest.getEngineNumber());
                    oldRequest.setInsuranceName(loanRequest.getInsuranceName());
                    oldRequest.setPremiumAmount(loanRequest.getPremiumAmount());
                    oldRequest.setInsuranceAmount(loanRequest.getInsuranceAmount());
                    oldRequest.setInsureStartDate(loanRequest.getInsureStartDate());
                    oldRequest.setInsureEndDate(loanRequest.getInsureEndDate());
                    oldRequest.setInsuranceCoverNo(loanRequest.getInsuranceCoverNo());
                    oldRequest.setInvoiceUnit(loanRequest.getInvoiceUnit());
                } else if (request.getParameter(ACTION_bookingApprove) != null || request.getParameter(ACTION_bookingDeny) != null) { // booking
                    oldRequest.setInvoiceProvided(loanRequest.isInvoiceProvided());
                    if (oldRequest.getDealer().isInsuranceChannel()) {
                        oldRequest.setTheftInsuranceComplete(loanRequest.isTheftInsuranceComplete());
                    }
                    oldRequest.setAuthorizationSigned(loanRequest.isAuthorizationSigned());
                    oldRequest.setDamageInsuranceComplete(loanRequest.isDamageInsuranceComplete());
                    oldRequest.setFacePhotoed(loanRequest.isFacePhotoed());
                    oldRequest.setContactSigned(loanRequest.isContactSigned());
                    oldRequest.setResponseInsuranceComplete(loanRequest.isResponseInsuranceComplete());
                    oldRequest.setMortgaged(loanRequest.isMortgaged());
                    oldRequest.setLunuoSafe(loanRequest.isLunuoSafe());
                    oldRequest.setMustInsurance(loanRequest.isMustInsurance());
                } else if (request.getParameter(ACTION_bankLoanApprove) != null) { // bank
                    oldRequest.setLoanDate(loanRequest.getLoanDate());
                    oldRequest.setBankContractNo(loanRequest.getBankContractNo());
                    oldRequest.setCreditCardNo(loanRequest.getCreditCardNo());
                } else if (request.getParameter(ACTION_insuranceUploadPolicy) != null) { // bank
                    oldRequest.setCoverNumber(loanRequest.getCoverNumber());
                } else if (request.getParameter(ACTION_caSaveAudit) != null) {
                    oldRequest.setIdentityCert(loanRequest.getIdentityCert());
                    oldRequest.setAddressCert(loanRequest.getAddressCert());
                    oldRequest.setIncomeCert(loanRequest.getIncomeCert());
                    oldRequest.setDriveCert(loanRequest.getDriveCert());
                    oldRequest.setPropertyGuarented(loanRequest.isPropertyGuarented());
                    oldRequest.setPropertyArea(loanRequest.getPropertyArea());
                    oldRequest.setPricePerSquare(loanRequest.getPricePerSquare());
                    oldRequest.setCreditScore(loanRequest.getCreditScore());
                    oldRequest.setCreditScoreType(loanRequest.getCreditScoreType());
                    oldRequest.setXishu(loanRequest.getXishu());
                    oldRequest.setBasicPrice(loanRequest.getBasicPrice());
                    oldRequest.setAnnualMustCost(loanRequest.getAnnualMustCost());
                }
                oldRequest.setSingleAuditComment(loanRequest.getSingleAuditComment());
                oldRequest.setSingleDealerComment(loanRequest.getSingleDealerComment());
                loanRequest = oldRequest;
            }
        }

        if (request.getParameter(ACTION_batchReceive) != null && selectedIds != null) {
            if(selectedIds != null) {
                handleBatchReceive(loanRequest, selectedIds, loginUser);
                loanRequestManager.saveLoanRequest(loanRequest);
            }
            return "redirect:/loanRequestform?reqId=" + loanRequest.getId();
        }

        if (loanRequest.getLoanProductId() != null) {
            loanRequest.setLoanProduct(loanProductManager.get(loanRequest.getLoanProductId()));
        }



        // validate form first
        if (loanRequest.getPhase().equals(Phase.draft) || loanRequest.getPhase().equals(Phase.bank_credit_audit)) {
            if (request.getParameter("save") != null || request.getParameter("saveAndUpload") != null) {
                validateDraft(loanRequest, locale, errors);
            } else if (request.getParameter(ACTION_submitDraft) != null) {
                validateDraftSubmit(loanRequest, locale, errors);
            }
        } else if (loanRequest.getPhase().equals(Phase.dealer_submit) && request.getParameter("save") != null) {
            validateDealerSubmit(loanRequest, locale, errors);
        } else if (loanRequest.getPhase().equals(Phase.dealer_apply_loan) && request.getParameter("save") != null) {
            //no validate
        }else if (request.getParameter(ACTION_submitRequest) != null || request.getParameter("save") != null) {
            if (validator != null) { // validator is null during testing
                validator.validate(loanRequest, errors);
            }
            //if (!errors.hasErrors()) {
                validateCommon(loanRequest, locale, errors);
                validateLoanInfo(loanRequest, locale, errors);
            //}
        }

        boolean hasError = false;
        if (request.getParameter(ACTION_bankCreditApprove) != null || request.getParameter(ACTION_bankGotoCA) != null) {
            hasError = validateBankApproveRequest(loanRequest, request, locale, errors);
        } else if (request.getParameter(ACTION_bankCreditDeny) != null) {
            hasError = validateBankDenyRequest(loanRequest, request, locale, errors);
        } else if (request.getParameter(ACTION_ccApprove) != null) {
            hasError = validateFinishPBOC(loanRequest, request, locale, errors);
        } else if (request.getParameter(ACTION_caApprove) != null) {
            hasError = validateAcceptLoan(loanRequest, request, locale, errors);
        } else if (request.getParameter(ACTION_scaApprove) != null) {
            hasError = validateAcceptLoan(loanRequest, request, locale, errors);
        } else if (request.getParameter(ACTION_applyLoan) != null) {
            hasError = validateApplyLoan(loanRequest, request, locale, errors);
        } else if (request.getParameter(ACTION_cancelLoan) != null) {
            hasError = validateCancelLoan(loanRequest, request, locale, errors);
        } else if (request.getParameter(ACTION_bookingApprove) != null || request.getParameter(ACTION_bookingGotoBank) != null) {
            hasError = validateApproveLoanApply(loanRequest, request, locale, errors);
        } else if (request.getParameter(ACTION_bankLoanApprove) != null) {
            hasError = validateBankLoaned(loanRequest, request, locale, errors);
        } else if (request.getParameter(ACTION_insuranceUploadPolicy) != null) {
            hasError = validateUploadPolicy(loanRequest, request, locale, errors);
        } else if (request.getParameter(ACTION_qualificationBack) != null || request.getParameter(ACTION_insuranceLoanBack) != null || request.getParameter(ACTION_bankLoanBack) != null) {
            hasError = validateBackCommentRequest(loanRequest, request, locale, errors);
        } else if (request.getParameter(ACTION_scaBack) != null) {
            hasError = validateAuditBackCommentRequest(loanRequest, request, locale, errors);
        }

        // process audit comment and dealer comment
        String userAndTimeStr = DateUtil.convertDateToString(new Date()) + " " + loginUser.getUsername() + " ";
        if (!StringUtil.isBlankOrNull(loanRequest.getSingleDealerComment())) {
            if (StringUtil.isBlankOrNull(loanRequest.getDealerComment())) {
                loanRequest.setDealerComment(userAndTimeStr + loanRequest.getSingleDealerComment());
            } else {
                loanRequest.setDealerComment(loanRequest.getDealerComment() + "\n" + userAndTimeStr + loanRequest.getSingleDealerComment());
            }
        }
        if (!StringUtil.isBlankOrNull(loanRequest.getSingleAuditComment())) {
            if (StringUtil.isBlankOrNull(loanRequest.getAuditComment())) {
                loanRequest.setAuditComment(userAndTimeStr + loanRequest.getSingleAuditComment());
            } else {
                loanRequest.setAuditComment(loanRequest.getAuditComment() + "\n" + userAndTimeStr + loanRequest.getSingleAuditComment());
            }
        }

        if (errors.hasErrors() || hasError) { // don't validate when deleting
            loanRequest = loanRequestManager.saveLoanRequest(loanRequest);
            if (loanRequest.getPhase().equals(Phase.draft)) {
                copyErrors(request, errors);
                return "redirect:/loanRequestform?reqId=" + loanRequest.getId();
            } else if (loanRequest.getPhase().equals(Phase.dealer_submit)) {
                copyErrors(request, errors);
                return "redirect:/loanRequestform?reqId=" + loanRequest.getId();
            }
            else if (loanRequest.getPhase().equals(Phase.ca_audit) || loanRequest.getPhase().equals(Phase.sca_audit)) {
                copyErrors(request, errors);
                return "redirect:/loanRequestform?reqId=" + loanRequest.getId();
            } else {
                copyErrors(request, errors);
                return "redirect:/loanRequestform?reqId=" + loanRequest.getId();
            }
        }

        if (log.isDebugEnabled()) {
            log.debug("process request form submission " + loanRequest.getNumber());
        }

        if (!loanRequest.isCoLoaned()) {
            loanRequest.setCoPerson(null);
            loanRequest.setCoPersonCreditQuestionnaire(null);
        }
        if (!loanRequest.isGuaranted()) {
            loanRequest.setDbPerson(null);
            loanRequest.setDbPersonCreditQuestionnaire(null);
        }

        String key = (isNew) ? "loanRequest.added" : "loanRequest.updated";
        success = "redirect:/loanRequestform?reqId=" + loanRequest.getId();

        if (request.getParameter(ACTION_scaApprove) != null) { // sca
            handleSubmitDecision(loanRequest, locale, loginUser);
            key = "ACTION_scaApprove.success";
        } else if(request.getParameter(ACTION_caSaveCredit)!=null){
            success = "redirect:/loanRequestform?reqId=" + loanRequest.getId();
            key = "loanRequest.updated";
        }
        else if (request.getParameter("save") == null && request.getParameter("saveAndUpload") == null) {
            Action action = getAction(loanRequest, loginUser, request);
            if (action == null) {
                throw new IllegalAccessException("You have no right to submit this request");
            }

            handleAction(action, loanRequest, locale, loginUser);
            key = "ACTION_" + action.getName() + ".success";
        }

        if (request.getParameter(ACTION_submitDraft) != null) { // dealer
            loanRequest.setRequestDate(new Date());
        } /*else if (request.getParameter(ACTION_bankCreditApprove) != null) { // bank
            handleBankApproveRequest(loanRequest, locale, loginUser);
            key = "ACTION_bankCreditApprove.success";
        } else if (request.getParameter(ACTION_bankGotoCA) != null) { // bank
            handleBankGotoCARequest(loanRequest, locale, loginUser);
            key = "ACTION_bankGotoCA.success";
        } */else if (request.getParameter(ACTION_bankCreditDeny) != null) { // bank
            loanRequest.setDecideDate(new Date());
        } /*else if (request.getParameter(ACTION_submitRequest) != null) { // dealer
            handleSubmitRequest(loanRequest, locale, loginUser);
            key = "ACTION_submitRequest.success";
        } else if (request.getParameter(ACTION_bondRequestApprove) != null) { // bond
            handleBondApproveRequest(loanRequest, locale, loginUser);
            key = "ACTION_bondRequestApprove.success";
        } */else if (request.getParameter(ACTION_bondRequestDeny) != null) { // bond
            loanRequest.setDecideDate(new Date());
        } else if (request.getParameter(ACTION_ccApprove) != null) { // cc
            TalkRecord talkRecord = new TalkRecord();
            talkRecord.setOperator(loginUser.getUsername());
            talkRecord.setTime(new Date());
            talkRecord.setContent(loanRequest.getPbocComment());
            talkRecord.setLoanRequest(loanRequest);
            loanRequest.getTalkRecordList().add(talkRecord);
        } /*else if (request.getParameter(ACTION_caApprove) != null) { // ca
            handleAdviceLoan(loanRequest, locale, loginUser);
            key = "ACTION_caApprove.success";
        } else if (request.getParameter(ACTION_scaApprove) != null) { // sca
            handleSubmitDecision(loanRequest, locale, loginUser);
            key = "ACTION_scaApprove.success";
        } *//*else if (request.getParameter(ACTION_qualificationApprove) != null) { // insurance qulification
            handleApproveQualification(loanRequest, locale, loginUser);
            key = "ACTION_qualificationApprove.success";
        } else if (request.getParameter(ACTION_applyLoan) != null) { // dealer apply loan
            handleApplyLoan(loanRequest, locale, loginUser);
            key = "ACTION_applyLoan.success";
        } else if (request.getParameter(ACTION_cancelLoan) != null) { // dealer cancel loan
            handleCancelLoan(loanRequest, locale, loginUser);
            key = "ACTION_cancelLoan.success";
        } else if (request.getParameter(ACTION_bondLoanApprove) != null) { // bond
            handleBondApproveLoan(loanRequest, locale, loginUser);
            key = "ACTION_bondLoanApprove.success";
        } */else if (request.getParameter(ACTION_bondLoanDeny) != null) { // bond
            loanRequest.setDecideDate(new Date());
        } else if (request.getParameter(ACTION_bookingApprove) != null) { // booking
            loanRequest.setCanPrepay(true);
        } else if (request.getParameter(ACTION_bookingDeny) != null) { // booking
            loanRequest.setDecideDate(new Date());
        } else if (request.getParameter(ACTION_bookingCanPrepay) != null) { // booking
            loanRequest.setCanPrepay(true);
        } /*else if (request.getParameter(ACTION_bookingGotoBank) != null) { // booking
            handleGotoBankAudit(loanRequest, locale, loginUser);
            key = "ACTION_bookingGotoBank.success";
        } else if (request.getParameter(ACTION_insuranceLoanApprove) != null) { // insurance
            handleApproveLoanBank(loanRequest, locale, loginUser);
            key = "ACTION_insuranceLoanApprove.success";
        }*/ /*else if (request.getParameter(ACTION_insuranceUploadCover) != null) { // insurance
            handleUploadCover(loanRequest, locale, loginUser);
            key = "ACTION_insuranceLoanApprove.success";
        } */ /*else if (request.getParameter(ACTION_bankLoanApprove) != null) { // bank
            handleApproveInsurance(loanRequest, locale, loginUser);
            key = "ACTION_bankLoanApprove.success";
        } else if (request.getParameter(ACTION_bankLoaned) != null) { // bank
            handleBankLoaned(loanRequest, locale, loginUser);
            key = "ACTION_bankLoaned.success";
        } else if (request.getParameter(ACTION_insuranceConfirmPolicy) != null) { // insurance
            handleConfirmPolicy(loanRequest, locale, loginUser);
            key = "ACTION_insuranceConfirmPolicy.success";
        } else if (request.getParameter(ACTION_insuranceUploadPolicy) != null) { // insurance
            handleUploadPolicy(loanRequest, locale, loginUser);
            key = "ACTION_insuranceUploadPolicy.success";
        } else if (request.getParameter(ACTION_scaBack) != null) { // sca back
            handleBackToCA(loanRequest, locale, loginUser);
            key = "ACTION_scaBack.success";
        } else if (request.getParameter(ACTION_qualificationBack) != null) { // qualification back
            handleBackQualification(loanRequest, locale, loginUser);
            key = "ACTION_qualificationBack.success";
        } else if (request.getParameter(ACTION_insuranceLoanBack) != null) { // insurance back
            handleBackInsurance(loanRequest, locale, loginUser);
            key = "ACTION_insuranceLoanBack.success";
        } else if (request.getParameter(ACTION_bankLoanBack) != null) { // bank back
            handleBackBankAudit(loanRequest, locale, loginUser);
            key = "ACTION_bankLoanBack.success";
        } else if (request.getParameter(ACTION_caBackDealer) != null) { // ca
            handleCABackDealer(loanRequest, locale, loginUser);
            key = "ACTION_caBackDealer.success";
        } else if (request.getParameter(ACTION_caBackBank) != null) { // ca
            handleCABackBank(loanRequest, locale, loginUser);
            key = "ACTION_caBackBank.success";
        }*/

        // contract no
        if (request.getParameter(ACTION_qualificationApprove) != null) {
            if (StringUtil.isBlankOrNull(loanRequest.getContractNo())) {
                loanRequest.setContractNo(getContractNumber());
            }
        } else if (request.getParameter(ACTION_submitRequest) != null && loanRequest.getStatus().equals(RequestStatus.loan_audit)) {
            if (loanRequest.getMaterialAudit().isLoanComplete()) { // go to next flow
                loanRequest.getMaterialAudit().setMaterialStatus(MaterialStatus.Auditing);
            }
        }

        // if copy request
        if (loanRequest.getCopyFromRequestId() != null) {
            LoanRequest orgLoanRequest = loanRequestManager.loadWholeLoanRequest(loanRequest.getCopyFromRequestId());
            if (orgLoanRequest.getPhase().equals(Phase.credit_denied)) {
                loanRequest.setStatus(RequestStatus.draft);
                loanRequest.setPhase(Phase.draft);
                loanRequest.setRequestPersonCreditQuestionnaire(null);
                loanRequest.setCoPersonCreditQuestionnaire(null);
                loanRequest.setDbPersonCreditQuestionnaire(null);
            } else {
                loanRequest.setStatus(RequestStatus.dealer_submit);
                loanRequest.setPhase(Phase.dealer_submit);
                boolean changed = false;
                if (orgLoanRequest.getRequestPerson().getName().equals(loanRequest.getRequestPerson().getName()) && orgLoanRequest.getRequestPerson().getIdNo().equals(loanRequest.getRequestPerson().getIdNo())) {
                    loanRequest.setRequestPersonCreditQuestionnaire(orgLoanRequest.getRequestPersonCreditQuestionnaire());
                } else {
                    changed = true;
                }
                if (loanRequest.isCoLoaned() != orgLoanRequest.isCoLoaned() || (loanRequest.isCoLoaned() && orgLoanRequest.isCoLoaned() &&
                        !(orgLoanRequest.getCoPerson().getName().equals(loanRequest.getCoPerson().getName()) && orgLoanRequest.getCoPerson().getIdNo().equals(loanRequest.getCoPerson().getIdNo())))) {
                    changed = true;
                } else {
                    loanRequest.setCoPersonCreditQuestionnaire(orgLoanRequest.getCoPersonCreditQuestionnaire());
                }
                if (loanRequest.isGuaranted() != orgLoanRequest.isGuaranted() || (loanRequest.isGuaranted() && orgLoanRequest.isGuaranted() &&
                        !(orgLoanRequest.getDbPerson().getName().equals(loanRequest.getDbPerson().getName()) && orgLoanRequest.getDbPerson().getIdNo().equals(loanRequest.getDbPerson().getIdNo())))) {
                    changed = true;
                } else {
                    loanRequest.setDbPersonCreditQuestionnaire(orgLoanRequest.getDbPersonCreditQuestionnaire());
                }

                if (!changed) {
                    if (orgLoanRequest.getAttachmentList().size() > 0)
                        copyAttachment(orgLoanRequest, loanRequest);
                } else {
                    loanRequest.setStatus(RequestStatus.draft);
                    loanRequest.setPhase(Phase.draft);
                    loanRequest.setRequestPersonCreditQuestionnaire(null);
                    loanRequest.setCoPersonCreditQuestionnaire(null);
                    loanRequest.setDbPersonCreditQuestionnaire(null);
                }
            }

            loanRequest.setRequestDate(new Date());
            loanRequest.setDecideDate(null);
            loanRequest.setLoanDate(null);
        }

        loanRequest = loanRequestManager.saveLoanRequest(loanRequest);
        // sendMessage
        /*if (request.getParameter(ACTION_submitDraft) != null) { // dealer -> bank
            sendMessageForMessage(loanRequest);
        } else */
        if (request.getParameter(ACTION_bondRequestApprove) != null || request.getParameter(ACTION_submitRequest) != null) { // bond -> cc rule process
            if (loanRequest.getStatus().equals(RequestStatus.processing_rule)) {
                sendMessageForRule(loanRequest);
            }
        } else if (request.getParameter(ACTION_scaApprove) != null) { // sca -> slave
            if (loanRequest.getPhase().equals(Phase.insurance_confirm_cover)) {
                sendConfirmCoverMessageForMessage(loanRequest);
                sendDelayedMessageForAudit(loanRequest);
            }
        } else if (request.getParameter(ACTION_insuranceConfirmPolicy) != null) { // sca -> slave
            if (loanRequest.getPhase().equals(Phase.insurance_upload_policy)) {
                sendQualificationAuditMessageForMessage(loanRequest);
                //sendDelayedMessageForMessage(loanRequest);
            }
        } else if (request.getParameter(ACTION_bookingApprove) != null) { // booking -> slave
            //sendMessageForMessage(loanRequest);
            //sendDelayedMessageForMessage(loanRequest);
        } else if (request.getParameter(ACTION_insuranceLoanApprove) != null) { // insurance -> master
            //sendMessageForMessage(loanRequest);
        } else if (request.getParameter(ACTION_bankLoaned) != null) { // bank -> slave
            //sendMessageForMessage(loanRequest);
            //sendDelayedMessageForMessage(loanRequest);
        } else if ((request.getParameter(ACTION_bankLoanApprove) != null || request.getParameter(ACTION_insuranceConfirmPolicy) != null) && loanRequest.getPhase().equals(Phase.insurance_upload_policy)) { // insurance -> master
            sendPolicyMessageForMessage(loanRequest);
        }

        if ((request.getParameter("save") != null ||  request.getParameter("saveAndUpload") !=null) && !isNew && !(loanRequest.getPhase().equals(Phase.bank_credit_audit) || loanRequest.getPhase().equals(Phase.draft))) {
            loanRequest.setSingleDealerComment("");
            loanRequest.setSingleAuditComment("");
            if(request.getParameter("saveAndUpload") !=null) {
                success="redirect:/attachments?reqId=" + loanRequest.getId();
            }
            else {
                success = "redirect:/loanRequestform?reqId=" + loanRequest.getId();
            }
        } else if ((request.getParameter("save") != null ||  request.getParameter("saveAndUpload")!=null) && !isNew && (loanRequest.getPhase().equals(Phase.bank_credit_audit) || loanRequest.getPhase().equals(Phase.draft))) {
            if(request.getParameter("saveAndUpload") !=null) {
                success="redirect:/attachments?reqId=" + loanRequest.getId();
            }
            else {
                success = "redirect:/loanRequestform?reqId=" + loanRequest.getId();
            }
        } else if (request.getParameter("cancelRequest") == null)
            success = "redirect:/loanRequestform?reqId=" + loanRequest.getId();

        if ((request.getParameter("save") != null ||  request.getParameter("saveAndUpload") !=null) && !isNew && (loginUser.hasRole(Constants.CA_ROLE) || loginUser.hasRole(Constants.SCA_ROLE))) {
            if(request.getParameter("saveAndUpload") !=null) {
                success="redirect:/attachments?reqId=" + loanRequest.getId();
            }
            else {
                success = "redirect:/loanRequestform?reqId=" + loanRequest.getId();
            }
        }
        saveMessage(request, getText(key, locale));

        return success;
    }



    private void copyErrors(HttpServletRequest request, BindingResult errors) {
        List<ObjectError> errorMessages = errors.getAllErrors();
        for (ObjectError err : errorMessages) {
            saveError(request, getText(err.getCode(), err.getArguments(), request.getLocale()));
        }
    }

    private void validateDraft(LoanRequest loanRequest, Locale locale, BindingResult errors) {
        LoanPerson requestPerson = loanRequest.getRequestPerson();
        if (requestPerson != null && StringUtil.isBlankOrNull(requestPerson.getName())) {
            errors.rejectValue("requestPerson.name", "errors.required", new String[]{getText("loanPerson.name", locale)}, "request person name is required");
        }
        if (requestPerson != null && requestPerson.getIdType() == null) {
            errors.rejectValue("requestPerson.idType", "errors.required", new String[]{getText("loanPerson.idType", locale)}, "request person id type is required");
        }
        if (requestPerson != null && StringUtil.isBlankOrNull(requestPerson.getIdNo())) {
            errors.rejectValue("requestPerson.idNo", "errors.required", new String[]{getText("loanPerson.idNo", locale)}, "request person id no is required");
        }
        if (requestPerson != null && requestPerson.getDueDate()==null) {
            errors.rejectValue("requestPerson.dueDate", "errors.required", new String[]{getText("loanPerson.dueDate", locale)}, "request person id dueDate is required");
        }
    }

    private void validateDealerSubmit(LoanRequest loanRequest, Locale locale, BindingResult errors) {
        LoanPerson requestPerson = loanRequest.getRequestPerson();
        if (requestPerson != null && StringUtil.isBlankOrNull(requestPerson.getName())) {
            errors.rejectValue("requestPerson.name", "errors.required", new String[]{getText("loanPerson.name", locale)}, "request person name is required");
        }
        if (requestPerson != null && requestPerson.getIdType() == null) {
            errors.rejectValue("requestPerson.idType", "errors.required", new String[]{getText("loanPerson.idType", locale)}, "request person id type is required");
        }
        if (requestPerson != null && StringUtil.isBlankOrNull(requestPerson.getIdNo())) {
            errors.rejectValue("requestPerson.idNo", "errors.required", new String[]{getText("loanPerson.idNo", locale)}, "request person id no is required");
        }
    }

    private void validateDraftSubmit(LoanRequest loanRequest, Locale locale, BindingResult errors) {
        LoanPerson requestPerson = loanRequest.getRequestPerson();
        LoanProduct loanProduct = loanRequest.getLoanProduct();
        ArrayList<String> ids = new ArrayList<String>();
        if (requestPerson != null && requestPerson.getDueDate()==null) {
            errors.rejectValue("requestPerson.dueDate", "errors.required", new String[]{getText("requestPerson.dueDate", locale)}, "request person id dueDate is required");
        }
        if (IDType.Identity.equals(requestPerson.getIdType()) && !StringUtil.isBlankOrNull(requestPerson.getIdNo()) && IdCardValidator.valideIdCard(requestPerson.getIdNo(), requestPerson.getBirthday()) != 0) {
            errors.rejectValue("requestPerson.idNo", "errors.invalid", new String[]{getText("loanPerson.idNo", locale)}, "request person id no is invalid");
        }
        if (!StringUtil.isBlankOrNull(requestPerson.getIdNo())) {
            ids.add(requestPerson.getIdNo());
        }
        if (loanProduct == null) {
            errors.rejectValue("loanProductId", "errors.required", new String[]{getText("loanRequest.loanProductId", locale)}, "loanProductId is required");
        }
        if (loanRequest.isCoLoaned()) {
            LoanPerson coPerson = loanRequest.getCoPerson();
            if (!StringUtil.isBlankOrNull(coPerson.getIdNo())) {
                ids.add(coPerson.getIdNo());
            }
            if (coPerson != null && coPerson.getDueDate()==null) {
                errors.rejectValue("coPerson.dueDate", "errors.required", new String[]{getText("coPerson.dueDate", locale)}, "co person id dueDate is required");
            }
            if (IDType.Identity.equals(coPerson.getIdType()) && !StringUtil.isBlankOrNull(coPerson.getIdNo()) && IdCardValidator.valideIdCard(coPerson.getIdNo(), coPerson.getBirthday()) != 0) {
                errors.rejectValue("coPerson.idNo", "errors.invalid", new String[]{getText("loanPerson.idNo", locale)}, "co person id no is invalid");
            }
        }
        if (loanRequest.isGuaranted()) {
            LoanPerson dbPerson = loanRequest.getDbPerson();
            if (!StringUtil.isBlankOrNull(dbPerson.getIdNo())) {
                ids.add(dbPerson.getIdNo());
            }
            if (dbPerson != null && dbPerson.getDueDate()==null) {
                errors.rejectValue("dbPerson.dueDate", "errors.required", new String[]{getText("dbPerson.dueDate", locale)}, "db person id dueDate is required");
            }
            if (IDType.Identity.equals(dbPerson.getIdType()) && !StringUtil.isBlankOrNull(dbPerson.getIdNo()) && IdCardValidator.valideIdCard(dbPerson.getIdNo(), dbPerson.getBirthday()) != 0) {
                errors.rejectValue("dbPerson.idNo", "errors.invalid", new String[]{getText("loanPerson.idNo", locale)}, "db person id no is invalid");
            }
        }
        Collection<String> result = new LinkedHashSet<String>(ids);
        if (ids.size() != result.size()) {
            errors.rejectValue(null, "errors.duplicate.id", "there are duplicate ids.");
        }
    }

    private void validateCommon(LoanRequest loanRequest, Locale locale, BindingResult errors) {
        ArrayList<String> nos = new ArrayList<String>();
        ArrayList<String> ids = new ArrayList<String>();
        // check mobile and identity no
        LoanPerson requestPerson = loanRequest.getRequestPerson();
        if (requestPerson != null && requestPerson.getDueDate()==null) {
            errors.rejectValue("requestPerson.dueDate", "errors.required", new String[]{getText("requestPerson.dueDate", locale)}, "request person id dueDate is required");
        }
        if (IDType.Identity.equals(requestPerson.getIdType()) && !StringUtil.isBlankOrNull(requestPerson.getIdNo()) && IdCardValidator.valideIdCard(requestPerson.getIdNo(), requestPerson.getBirthday()) != 0) {
            errors.rejectValue("requestPerson.idNo", "errors.invalid", new String[]{getText("loanPerson.idNo", locale)}, "request person id no is invalid");
        }
        if (!MobileFromUtil.isValid(requestPerson.getMobileNo())) {
            errors.rejectValue("requestPerson.mobileNo", "errors.mobile", new String[]{getText("loanPerson.mobileNo", locale)}, "request person mobile no is invalid");
        }
        if (requestPerson.getAddress().getAddress().length() < 8) {
            errors.rejectValue("requestPerson.address.address", "errors.address", new String[]{getText("loanRequest.address", locale)}, "request person address is too short");
        }
        if (requestPerson.getCompanyAddress().getAddress().length() < 8) {
            errors.rejectValue("requestPerson.companyAddress.address", "errors.address", new String[]{getText("loanRequest.companyAddress", locale)}, "request person company Address is too short");
        }
        if (!StringUtil.isBlankOrNull(requestPerson.getIdNo())) {
            ids.add(requestPerson.getIdNo());
        }
        if (!StringUtil.isBlankOrNull(requestPerson.getMobileNo()))
            nos.add(requestPerson.getMobileNo());
        if (!StringUtil.isBlankOrNull(requestPerson.getHomeTelNo()))
            nos.add(requestPerson.getHomeTelNo());
        if (!StringUtil.isBlankOrNull(requestPerson.getWorkTelNo()))
            nos.add(requestPerson.getWorkTelNo());
        // check address and postal
        if (StringUtil.isBlankOrNull(requestPerson.getAddress().getProvince())
                || StringUtil.isBlankOrNull(requestPerson.getAddress().getCity()) || StringUtil.isBlankOrNull(requestPerson.getAddress().getAddress())){
            errors.rejectValue("requestPerson.address.address", "errors.required", new String[]{getText("loanRequest.address", locale)}, "request person address is required");
        }
        if (StringUtil.isBlankOrNull(requestPerson.getCompanyAddress().getProvince())
                || StringUtil.isBlankOrNull(requestPerson.getCompanyAddress().getCity()) || StringUtil.isBlankOrNull(requestPerson.getCompanyAddress().getAddress())){
            errors.rejectValue("requestPerson.companyAddress.address", "errors.required", new String[]{getText("loanRequest.companyAddress", locale)}, "request person companyAddress address is required");
        }
        if (StringUtil.isBlankOrNull(requestPerson.getHkAddress().getProvince())
                || StringUtil.isBlankOrNull(requestPerson.getHkAddress().getCity()) || StringUtil.isBlankOrNull(requestPerson.getHkAddress().getAddress())){
            errors.rejectValue("requestPerson.hkAddress.address", "errors.required", new String[]{getText("loanRequest.hkAddress", locale)}, "request person companyAddress address is required");
        }
        if(StringUtil.isBlankOrNull(requestPerson.getAddress().getPostalCode())){
            errors.rejectValue("requestPerson.address.postalCode", "errors.required", new String[]{getText("user.address.postalCode", locale)}, "request person address postal code is required");
        }
        if(StringUtil.isBlankOrNull(requestPerson.getCompanyAddress().getPostalCode())){
            errors.rejectValue("requestPerson.companyAddress.postalCode", "errors.required", new String[]{getText("user.address.postalCode", locale)}, "request person company address postal code is required");
        }
        if(StringUtil.isBlankOrNull(requestPerson.getHkAddress().getPostalCode())){
            errors.rejectValue("requestPerson.hkAddress.postalCode", "errors.required", new String[]{getText("user.address.postalCode", locale)}, "request person hkaddress postal code is required");
        }

        //setIdentity(requestPerson);
        //setMobileLocation(loanRequest.getRequestPerson());
        if (loanRequest.isCoLoaned()) {
            LoanPerson coPerson = loanRequest.getCoPerson();
            if (!StringUtil.isBlankOrNull(coPerson.getIdNo())) {
                ids.add(coPerson.getIdNo());
            }
            if (coPerson != null && coPerson.getDueDate()==null) {
                errors.rejectValue("coPerson.dueDate", "errors.required", new String[]{getText("coPerson.dueDate", locale)}, "co person id dueDate is required");
            }
            if (IDType.Identity.equals(coPerson.getIdType()) && !StringUtil.isBlankOrNull(coPerson.getIdNo()) && IdCardValidator.valideIdCard(coPerson.getIdNo(), coPerson.getBirthday()) != 0) {
                errors.rejectValue("coPerson.idNo", "errors.invalid", new String[]{getText("loanPerson.idNo", locale)}, "co person id no is invalid");
            }
            // check address and postal
            if (StringUtil.isBlankOrNull(coPerson.getAddress().getProvince())
                    || StringUtil.isBlankOrNull(coPerson.getAddress().getCity()) || StringUtil.isBlankOrNull(coPerson.getAddress().getAddress())){
                errors.rejectValue("coPerson.address.address", "errors.required", new String[]{getText("loanRequest.address", locale)}, "co person address is required");
            }
            if (StringUtil.isBlankOrNull(requestPerson.getCompanyAddress().getProvince())
                    || StringUtil.isBlankOrNull(requestPerson.getCompanyAddress().getCity()) || StringUtil.isBlankOrNull(requestPerson.getCompanyAddress().getAddress())){
                errors.rejectValue("requestPerson.companyAddress.address", "errors.required", new String[]{getText("loanRequest.companyAddress", locale)}, "request person companyAddress address is required");
            }
            if (StringUtil.isBlankOrNull(requestPerson.getHkAddress().getProvince())
                    || StringUtil.isBlankOrNull(requestPerson.getHkAddress().getCity()) || StringUtil.isBlankOrNull(requestPerson.getHkAddress().getAddress())){
                errors.rejectValue("requestPerson.hkAddress.address", "errors.required", new String[]{getText("loanRequest.hkAddress", locale)}, "request person companyAddress address is required");
            }
            //setMobileLocation(coPerson);
            //setIdentity(coPerson);
            if (!MobileFromUtil.isValid(coPerson.getMobileNo())) {
                errors.rejectValue("coPerson.mobileNo", "errors.mobile", new String[]{getText("coPerson.mobileNo", locale)}, "co person mobile no is invalid");
            }
            if (coPerson.getAddress().getAddress().length() < 8) {
                errors.rejectValue("coPerson.address.address", "errors.address", new String[]{getText("loanRequest.address", locale)}, "co person address is too short");
            }
            if (coPerson.getCompanyAddress().getAddress().length() < 8) {
                errors.rejectValue("coPerson.companyAddress.address", "errors.address", new String[]{getText("loanRequest.companyAddress", locale)}, "co person company Address is too short");
            }
            if (!StringUtil.isBlankOrNull(coPerson.getMobileNo()))
                nos.add(coPerson.getMobileNo());
            if (!StringUtil.isBlankOrNull(coPerson.getHomeTelNo()))
                nos.add(coPerson.getHomeTelNo());
            if (!StringUtil.isBlankOrNull(coPerson.getWorkTelNo()))
                nos.add(coPerson.getWorkTelNo());
        }
        if (loanRequest.isGuaranted()) {
            LoanPerson dbPerson = loanRequest.getDbPerson();
            if (!StringUtil.isBlankOrNull(dbPerson.getIdNo())) {
                ids.add(dbPerson.getIdNo());
            }
            if (dbPerson != null && dbPerson.getDueDate()==null) {
                errors.rejectValue("dbPerson.dueDate", "errors.required", new String[]{getText("dbPerson.dueDate", locale)}, "db person id dueDate is required");
            }
            if (IDType.Identity.equals(dbPerson.getIdType()) && !StringUtil.isBlankOrNull(dbPerson.getIdNo()) && IdCardValidator.valideIdCard(dbPerson.getIdNo(), dbPerson.getBirthday()) != 0) {
                errors.rejectValue("dbPerson.idNo", "errors.invalid", new String[]{getText("loanPerson.idNo", locale)}, "db person id no is invalid");
            }
            if (dbPerson != null && dbPerson.getDueDate()==null) {
                    errors.rejectValue("dbPerson.dueDate", "errors.required", new String[]{getText("dbPerson.dueDate", locale)}, "db person id dueDate is required");
            }
            // check address and postal
            if (StringUtil.isBlankOrNull(dbPerson.getAddress().getProvince())
                    || StringUtil.isBlankOrNull(dbPerson.getAddress().getCity()) || StringUtil.isBlankOrNull(dbPerson.getAddress().getAddress())){
                errors.rejectValue("dbPerson.address.address", "errors.required", new String[]{getText("loanRequest.address", locale)}, "request person address is required");
            }
            if (StringUtil.isBlankOrNull(requestPerson.getCompanyAddress().getProvince())
                    || StringUtil.isBlankOrNull(requestPerson.getCompanyAddress().getCity()) || StringUtil.isBlankOrNull(requestPerson.getCompanyAddress().getAddress())){
                errors.rejectValue("requestPerson.companyAddress.address", "errors.required", new String[]{getText("loanRequest.companyAddress", locale)}, "request person companyAddress address is required");
            }
            if (StringUtil.isBlankOrNull(requestPerson.getHkAddress().getProvince())
                    || StringUtil.isBlankOrNull(requestPerson.getHkAddress().getCity()) || StringUtil.isBlankOrNull(requestPerson.getHkAddress().getAddress())){
                errors.rejectValue("requestPerson.hkAddress.address", "errors.required", new String[]{getText("loanRequest.hkAddress", locale)}, "request person companyAddress address is required");
            }
            /*if(StringUtil.isBlankOrNull(dbPerson.getAddress().getPostalCode())){
                errors.rejectValue("dbPerson.address.postalCode", "errors.required", new String[]{getText("user.address.postalCode", locale)}, "request person address postal code is required");
            }
            if(StringUtil.isBlankOrNull(requestPerson.getCompanyAddress().getPostalCode())){
                errors.rejectValue("requestPerson.companyAddress.postalCode", "errors.required", new String[]{getText("user.address.postalCode", locale)}, "request person company address postal code is required");
            }
            if(StringUtil.isBlankOrNull(requestPerson.getHkAddress().getPostalCode())){
                errors.rejectValue("requestPerson.hkAddress.postalCode", "errors.required", new String[]{getText("user.address.postalCode", locale)}, "request person hkaddress postal code is required");
            }*/
            //setMobileLocation(dbPerson);
            //setIdentity(dbPerson);
            if (!MobileFromUtil.isValid(dbPerson.getMobileNo())) {
                errors.rejectValue("dbPerson.mobileNo", "errors.mobile", new String[]{getText("dbPerson.mobileNo", locale)}, "guaranted person mobile no is invalid");
            }
            if (dbPerson.getAddress().getAddress().length() < 8) {
                errors.rejectValue("coPerson.address.address", "errors.address", new String[]{getText("loanRequest.address", locale)}, "guaranted person address is too short");
            }
            if (dbPerson.getCompanyAddress().getAddress().length() < 8) {
                errors.rejectValue("dbPerson.companyAddress.address", "errors.address", new String[]{getText("loanRequest.companyAddress", locale)}, "guaranted person company Address is too short");
            }
            if (!StringUtil.isBlankOrNull(dbPerson.getMobileNo()))
                nos.add(dbPerson.getMobileNo());
            if (!StringUtil.isBlankOrNull(dbPerson.getHomeTelNo()))
                nos.add(dbPerson.getHomeTelNo());
            if (!StringUtil.isBlankOrNull(dbPerson.getWorkTelNo()))
                nos.add(dbPerson.getWorkTelNo());
        }
        // check urgency contact
        if (!MobileFromUtil.isValid(loanRequest.getUrgentContactTelNo1())) {
            errors.rejectValue("urgentContactTelNo1", "errors.mobile", new String[]{getText("loanRequest.urgentContactTelNo1", locale)}, "urgent contact mobile no is invalid");
        }
        if (!StringUtil.isBlankOrNull(loanRequest.getUrgentContactName2()) || !StringUtil.isBlankOrNull(loanRequest.getUrgentContactRelation2()) || !StringUtil.isBlankOrNull(loanRequest.getUrgentContactTelNo2())) {
            if (StringUtil.isBlankOrNull(loanRequest.getUrgentContactName2()) || StringUtil.isBlankOrNull(loanRequest.getUrgentContactRelation2()) || StringUtil.isBlankOrNull(loanRequest.getUrgentContactTelNo2())) {
                errors.rejectValue(null, "errors.urgent.contact2.incomplete", "urgent contact2 info no is incomplete");
            }
        }
        if (!StringUtil.isBlankOrNull(loanRequest.getUrgentContactName3()) || !StringUtil.isBlankOrNull(loanRequest.getUrgentContactRelation3()) || !StringUtil.isBlankOrNull(loanRequest.getUrgentContactTelNo3())) {
            if (StringUtil.isBlankOrNull(loanRequest.getUrgentContactName3()) || StringUtil.isBlankOrNull(loanRequest.getUrgentContactRelation3()) || StringUtil.isBlankOrNull(loanRequest.getUrgentContactTelNo3())) {
                errors.rejectValue(null, "errors.urgent.contact3.incomplete", "urgent contact3 info no is incomplete");
            }
        }
        nos.add(loanRequest.getUrgentContactTelNo1());
        if (!StringUtil.isBlankOrNull(loanRequest.getUrgentContactTelNo2())) {
            nos.add(loanRequest.getUrgentContactTelNo2());
        }
        if (!StringUtil.isBlankOrNull(loanRequest.getUrgentContactTelNo3())) {
            nos.add(loanRequest.getUrgentContactTelNo3());
        }
        //check Number in the credit info
        /*if (!StringUtil.isBlankOrNull((loanRequest.getRequestPersonCreditQuestionnaire().getMobileNo()))){
            //nos.add((loanRequest.getRequestPersonCreditQuestionnaire().getMobileNo()));
            if (!requestPerson.getMobileNo().equals(loanRequest.getRequestPersonCreditQuestionnaire().getMobileNo())){
                errors.rejectValue(null, "errors.not.consist.mobile.request", "not consistant with credit info");
            }
        }
        if (loanRequest.getCoPersonCreditQuestionnaire() != null && !StringUtil.isBlankOrNull((loanRequest.getCoPersonCreditQuestionnaire().getMobileNo()))){
            //nos.add((loanRequest.getCoPersonCreditQuestionnaire().getMobileNo()));
            if(loanRequest.isCoLoaned() && (loanRequest.getCoPerson()==null || !loanRequest.getCoPerson().getMobileNo().equals(loanRequest.getCoPersonCreditQuestionnaire().getMobileNo()))){
                errors.rejectValue(null, "errors.not.consist.mobile.coperson", "not consistant with credit info");
            }
        }
        if (loanRequest.getDbPersonCreditQuestionnaire() != null && !StringUtil.isBlankOrNull((loanRequest.getDbPersonCreditQuestionnaire().getMobileNo()))){
            //nos.add((loanRequest.getDbPersonCreditQuestionnaire().getMobileNo()));
            if (loanRequest.isGuaranted() && (loanRequest.getDbPerson()==null || !loanRequest.getDbPerson().getMobileNo().equals(loanRequest.getDbPersonCreditQuestionnaire().getMobileNo()))){
                errors.rejectValue(null, "errors.not.consist.mobile.dbperson", "not consistant with credit info");
            }
        }*/

        Collection<String> result = new LinkedHashSet<String>(nos);
        if (nos.size() != result.size()) {
            errors.rejectValue(null, "errors.duplicate.number", "there are duplicate numbers.");
        }

        result = new LinkedHashSet<String>(ids);
        if (ids.size() != result.size()) {
            errors.rejectValue(null, "errors.duplicate.id", "there are duplicate ids.");
        }
    }

    private boolean validateBankApproveRequest(LoanRequest loanRequest, HttpServletRequest request, Locale locale, BindingResult errors) {
        boolean hasError = false;
        CreditQuestionnaire creditInfo = loanRequest.getRequestPersonCreditQuestionnaire();
        if (StringUtil.isBlankOrNull(creditInfo.getCreditLevel())) {
            saveError(request, getText("errors.required", new String[]{getText("loanRequest.creditLevel", locale)}, locale));
            hasError = true;
        }
        if (creditInfo.getCreditLevel().equals("B") || creditInfo.getCreditLevel().equals("2")){
            if(creditInfo.getMaritalStatus()==null){
                saveError(request, getText("errors.required", new String[]{getText("loanPerson.maritalStatus", locale)}, locale));
                hasError = true;
            }
            if(StringUtil.isBlankOrNull(creditInfo.getWorkCompany())){
                saveError(request, getText("errors.required", new String[]{getText("loanPerson.workCompany", locale)}, locale));
                hasError = true;
            }
            if(!MobileFromUtil.isValid(creditInfo.getMobileNo())){
                errors.rejectValue("requestPerson.mobileNo", "errors.mobile", new String[]{getText("loanPerson.mobileNo", locale)}, "request person mobile no is invalid");
            }
            if(StringUtil.isBlankOrNull(creditInfo.getHomeTelNo()) && StringUtil.isBlankOrNull(creditInfo.getWorkTelNo())){
                saveError(request, getText("errors.homeOrWork", locale));
                hasError = true;
            }
            if(creditInfo.getAddress()==null || StringUtil.isBlankOrNull(creditInfo.getAddress().getProvince())|| StringUtil.isBlankOrNull(creditInfo.getAddress().getCity())
                    || StringUtil.isBlankOrNull(creditInfo.getAddress().getCounty())||StringUtil.isBlankOrNull(creditInfo.getAddress().getAddress())){
                saveError(request, getText("errors.required", new String[]{getText("loanRequest.address", locale)}, locale));
                hasError = true;
            }
            if(creditInfo.getHkAddress()==null || StringUtil.isBlankOrNull(creditInfo.getHkAddress().getProvince())|| StringUtil.isBlankOrNull(creditInfo.getHkAddress().getCity())
                    || StringUtil.isBlankOrNull(creditInfo.getHkAddress().getCounty())||StringUtil.isBlankOrNull(creditInfo.getHkAddress().getAddress())){
                saveError(request, getText("errors.required", new String[]{getText("loanRequest.hkAddress", locale)}, locale));
                hasError = true;
            }
            if(creditInfo.getWorkAddress()==null || StringUtil.isBlankOrNull(creditInfo.getWorkAddress().getProvince())|| StringUtil.isBlankOrNull(creditInfo.getWorkAddress().getCity())
                    || StringUtil.isBlankOrNull(creditInfo.getWorkAddress().getCounty())||StringUtil.isBlankOrNull(creditInfo.getWorkAddress().getAddress())){
                saveError(request, getText("errors.required", new String[]{getText("loanRequest.companyAddress", locale)}, locale));
                hasError = true;
            }
            if(StringUtil.isBlankOrNull(creditInfo.getJob())){
                saveError(request, getText("errors.required", new String[]{getText("loanRequest.workPosition", locale)}, locale));
                hasError = true;
            }
            if(StringUtil.isBlankOrNull(creditInfo.getJoinCompanyYear())){
                saveError(request, getText("errors.required", new String[]{getText("loanPerson.joinCompanyYear", locale)}, locale));
                hasError = true;
            }
            if(creditInfo.getInfoUpdateDatetime()==null){
                saveError(request, getText("errors.required", new String[]{getText("loanPerson.infoUpdateDatetime", locale)}, locale));
                hasError = true;
            }
        }
        return hasError;
    }

    private boolean validateBankDenyRequest(LoanRequest loanRequest, HttpServletRequest request, Locale locale, BindingResult errors) {
        boolean hasError = false;
        if (StringUtil.isBlankOrNull(loanRequest.getSingleDealerComment())) {
            saveError(request, getText("errors.required", new String[]{getText("loanRequest.denyReason", locale)}, locale));
            hasError = true;
        }
        return hasError;
    }

    private boolean validateBackCommentRequest(LoanRequest loanRequest, HttpServletRequest request, Locale locale, BindingResult errors) {
        boolean hasError = false;
        if (StringUtil.isBlankOrNull(loanRequest.getSingleDealerComment())) {
            saveError(request, getText("errors.required", new String[]{getText("loanRequest.backReason", locale)}, locale));
            hasError = true;
        }
        return hasError;
    }

    private boolean validateAuditBackCommentRequest(LoanRequest loanRequest, HttpServletRequest request, Locale locale, BindingResult errors) {
        boolean hasError = false;
        if (StringUtil.isBlankOrNull(loanRequest.getSingleAuditComment())) {
            saveError(request, getText("errors.required", new String[]{getText("loanRequest.backReason", locale)}, locale));
            hasError = true;
        }
        return hasError;
    }

    private boolean validateCancelLoan(LoanRequest loanRequest, HttpServletRequest request, Locale locale, BindingResult errors) {
        boolean hasError = false;
        if (StringUtil.isBlankOrNull(loanRequest.getSingleDealerComment())) {
            saveError(request, getText("errors.required", new String[]{getText("loanRequest.cancelReason", locale)}, locale));
            hasError = true;
        }
        return hasError;
    }

    private boolean validateBankLoaned(LoanRequest loanRequest, HttpServletRequest request, Locale locale, BindingResult errors) {
        boolean hasError = false;
        if (loanRequest.getLoanDate() == null) {
            saveError(request, getText("errors.required", new String[]{getText("loanRequest.loanDate", locale)}, locale));
            hasError = true;
        }
        return hasError;
    }

    private boolean validateUploadPolicy(LoanRequest loanRequest, HttpServletRequest request, Locale locale, BindingResult errors) {
        boolean hasError = false;
        if (StringUtil.isBlankOrNull(loanRequest.getCoverNumber())) {
            saveError(request, getText("errors.required", new String[]{getText("loanRequest.coverNumber", locale)}, locale));
            hasError = true;
        }
        return hasError;
    }

    private boolean validateFinishPBOC(LoanRequest loanRequest, HttpServletRequest request, Locale locale, BindingResult errors) {
        boolean hasError = false;
        if (StringUtil.isBlankOrNull(loanRequest.getPbocComment())) {
            saveError(request, getText("errors.required", new String[]{getText("loanRequest.pbocComment", locale)}, locale));
            hasError = true;
        }
        return hasError;
    }

    private void validateAdviceLoan(LoanRequest loanRequest, Locale locale, BindingResult errors) {

    }

    private boolean validateAcceptLoan(LoanRequest loanRequest, HttpServletRequest request, Locale locale, BindingResult errors) {
        boolean hasError = false;
        if (StringUtil.isBlankOrNull(loanRequest.getAddressCert()) || StringUtil.isBlankOrNull(loanRequest.getIncomeCert()) || StringUtil.isBlankOrNull(loanRequest.getDriveCert())) {
            saveError(request, getText("errors.certificate.incomplete", locale));
            hasError = true;
        }
        if(loanRequest.getAuditCode().equals(AuditCode.changeApprove) || loanRequest.getAuditCode().equals(AuditCode.deny) || loanRequest.getAuditCode().equals(AuditCode.cancel)){
            if (StringUtil.isBlankOrNull(loanRequest.getSingleDealerComment()) || StringUtil.isBlankOrNull(loanRequest.getSingleAuditComment())) {
                saveError(request, getText("errors.required", new String[]{getText("loanRequest.auditComment", locale)}, locale));
                saveError(request, getText("errors.required", new String[]{getText("loanRequest.dealerComment", locale)}, locale));
                hasError = true;
            }
        }
        /*if (StringUtil.isBlankOrNull(loanRequest.getSingleDealerComment()) || StringUtil.isBlankOrNull(loanRequest.getSingleAuditComment())) {
            saveError(request, getText("errors.required", new String[]{getText("loanRequest.auditComment", locale)}, locale));
            hasError = true;
        }*/
        if (loanRequest.getAuditCode() == null) {
            saveError(request, getText("errors.required", new String[]{getText("loanRequest.auditCode", locale)}, locale));
            hasError = true;
        }
        return hasError;
    }

    private boolean validateApproveLoanApply(LoanRequest loanRequest, HttpServletRequest request, Locale locale, BindingResult errors) {
        boolean hasError = false;
        if (/*(loanRequest.getDealer().isInsuranceChannel() && loanRequest.isTheftInsuranceComplete()==false) ||*/
                (loanRequest.getDealer().isInsuranceChannel() && loanRequest.isTheftInsuranceComplete() == false) ||
                loanRequest.isResponseInsuranceComplete() == false ||
                loanRequest.isDamageInsuranceComplete() == false ||
                loanRequest.isContactSigned() == false ||
                loanRequest.isFacePhotoed() == false ||
                loanRequest.isAuthorizationSigned() == false ||
                loanRequest.isInvoiceProvided() == false ||
                (loanRequest.isMustInsurance()==false && loanRequest.isLunuoSafe()==false ) ||
                (!loanRequest.getDealer().isAllowNoMortgaged() && loanRequest.isMortgaged() == false)) {
            saveError(request, getText("errors.procedure.incomplete", locale));
            hasError = true;
        }
        return hasError;
    }

    private boolean validateApplyLoan(LoanRequest loanRequest, HttpServletRequest request, Locale locale, BindingResult errors) {
        boolean hasError = false;
        if (loanRequest.getVehicleManufactureDate() == null) {
            saveError(request, getText("errors.required", new String[]{getText("loanRequest.vehicleManufactureDate", locale)}, locale));
            hasError = true;
        }
        if (loanRequest.getVehiclePurchaseDate() == null) {
            saveError(request, getText("errors.required", new String[]{getText("loanRequest.vehiclePurchaseDate", locale)}, locale));
            hasError = true;
        }
        if (StringUtil.isBlankOrNull(loanRequest.getFrameNo())) {
            saveError(request, getText("errors.required", new String[]{getText("loanRequest.frameNo", locale)}, locale));
            hasError = true;
        }
        if (StringUtil.isBlankOrNull(loanRequest.getEngineNumber())) {
            saveError(request, getText("errors.required", new String[]{getText("loanRequest.engineNumber", locale)}, locale));
            hasError = true;
        }
        if (StringUtil.isBlankOrNull(loanRequest.getInsuranceName())) {
            saveError(request, getText("errors.required", new String[]{getText("loanRequest.insuranceName", locale)}, locale));
            hasError = true;
        }
        if (loanRequest.getPremiumAmount() <= 0) {
            saveError(request, getText("errors.required", new String[]{getText("loanRequest.premiumAmount", locale)}, locale));
            hasError = true;
        }
        if (loanRequest.getInsuranceAmount() <= 0) {
            saveError(request, getText("errors.required", new String[]{getText("loanRequest.insuranceAmount", locale)}, locale));
            hasError = true;
        }
        if (StringUtil.isBlankOrNull(loanRequest.getInsuranceCoverNo())) {
            saveError(request, getText("errors.required", new String[]{getText("loanRequest.insuranceCoverNo", locale)}, locale));
            hasError = true;
        }
        if (loanRequest.getInsureEndDate() == null) {
            saveError(request, getText("errors.required", new String[]{getText("loanRequest.insureEndDate", locale)}, locale));
            hasError = true;
        }
        if (loanRequest.getInsureStartDate() == null) {
            saveError(request, getText("errors.required", new String[]{getText("loanRequest.insureStartDate", locale)}, locale));
            hasError = true;
        }
        return hasError;
    }

    private void validateLoanInfo(LoanRequest loanRequest, Locale locale, BindingResult errors) {
        //check loan product
        LoanProduct loanProduct = loanRequest.getLoanProduct();
        if (loanProduct != null) {
            if (loanRequest.getLoanAmount() < loanProduct.getFaLL() || loanRequest.getLoanAmount() > loanProduct.getFaUL()) {
                errors.rejectValue("loanAmount", "errors.invalid", new String[]{getText("loanRequest.loanAmount", locale)}, "loan amount is invalid");
            }
            if (!loanProduct.getLoanYears().contains(loanRequest.getLoanYears())) {
                errors.rejectValue("loanYears", "errors.invalid", new String[]{getText("loanRequest.loanYears", locale)}, "loan years is invalid");
            }
            if (loanRequest.getFeeRate() < loanProduct.getCrLL() || loanRequest.getFeeRate() > loanProduct.getCrUL()) {
                errors.rejectValue("feeRate", "errors.invalid", new String[]{getText("loanRequest.feeRate", locale)}, "Fee rate is invalid");
            }
            if (loanRequest.getDownPaymentRate() < loanProduct.getDpLL() || loanRequest.getDownPaymentRate() > loanProduct.getDpUL()) {
                errors.rejectValue("downPaymentRate", "errors.invalid", new String[]{getText("loanRequest.downPaymentRate", locale)}, "Down Payment Rate is invalid");
            }
            /*if (Math.round(loanRequest.getMonthPaymentAmount())!=Math.round(calculateMonthPay(loanProduct.getCoef(), loanRequest.getFeeRate(),loanProduct.getCostRate(), loanRequest.getLoanAmount(), loanRequest.getLoanYears()))){
                errors.rejectValue("monthPaymentAmount", "errors.invalid", new String[]{getText("loanRequest.monthPaymentAmount", locale)}, "Month payment is invalid");
            }*/
//            BigDecimal feeRate = new BigDecimal(loanRequest.getFeeRate()).divide(BigDecimal.valueOf(100));
//            BigDecimal downPaymentReate = new BigDecimal(loanRequest.getDownPaymentRate()).divide(BigDecimal.valueOf(100));
//            BigDecimal result = BigDecimal.valueOf(1).add(feeRate).multiply(BigDecimal.valueOf(1).subtract(downPaymentReate));
//
//            if (result.floatValue() > 0.8 ){
//                errors.rejectValue("downPaymentRate", "errors.invalid", new String[]{getText("loanRequest.downPaymentRate", locale)}, "Down Payment Rate is invalid");
//                errors.rejectValue("feeRate", "errors.invalid", new String[]{getText("loanRequest.feeRate", locale)}, "Fee rate is invalid");
//            }
        }
    }

    private void restoreUnchanged(LoanRequest newRequest, LoanRequest oldRequest) {
        newRequest.setAuditUser(oldRequest.getAuditUser());
        newRequest.setDealerUser(oldRequest.getDealerUser());
        newRequest.setDealer(oldRequest.getDealer());
        newRequest.setStatus(oldRequest.getStatus());
        newRequest.setPhase(oldRequest.getPhase());
        //newRequest.setFeedbackType(oldRequest.getFeedbackType());
        newRequest.setRequestDate(oldRequest.getRequestDate());
        newRequest.setDecideDate(oldRequest.getDecideDate());
        newRequest.setAuditComment(oldRequest.getAuditComment());
        newRequest.setDealerComment(oldRequest.getDealerComment());

        newRequest.setActivities(oldRequest.getActivities());
        newRequest.setAttachmentList(oldRequest.getAttachmentList());
        newRequest.setTalkRecordList(oldRequest.getTalkRecordList());
        newRequest.setFeedbackList(oldRequest.getFeedbackList());
        newRequest.setRules(oldRequest.getRules());

        newRequest.setIdentityCert(oldRequest.getIdentityCert());
        newRequest.setAddressCert(oldRequest.getAddressCert());
        newRequest.setIncomeCert(oldRequest.getIncomeCert());
        newRequest.setDriveCert(oldRequest.getDriveCert());
        newRequest.setPropertyGuarented(oldRequest.isPropertyGuarented());
        newRequest.setPropertyArea(oldRequest.getPropertyArea());
        newRequest.setPricePerSquare(oldRequest.getPricePerSquare());

        newRequest.setMaterialAudit(oldRequest.getMaterialAudit());
    }

    private void setMobileLocation(LoanPerson loanPerson) {
        String mobileNo = loanPerson.getMobileNo();
        if (!StringUtil.isBlankOrNull(mobileNo)) {
            String from = MobileFromUtil.getMobileAddress(mobileNo);
            List<Province> provinces = provinceManager.getAll();
            for (Province province : provinces) {
                String provinceName = province.getName();
                if (from.indexOf(provinceName) != -1) {
                    loanPerson.setMobileProvince(provinceName);
                    List<City> cities = provinceManager.getMyCity(provinceName);
                    for (City city : cities) {
                        if (from.indexOf(city.getName()) != -1) {
                            loanPerson.setMobileCity(city.getName());
                            break;
                        }
                    }
                    break;
                }
            }
        }
    }

    private void setIdentity(LoanPerson loanPerson) {
        if (IDType.Identity.equals(loanPerson.getIdType()) && !StringUtil.isBlankOrNull(loanPerson.getIdNo())) {
            String code = IdCardValidator.getProvinceCode(loanPerson.getIdNo());
            String provinceName = provinceManager.getProvinceNameByCode(code);
            loanPerson.setIdProvince(provinceName);
        }
    }

    private String getUploadPath() {
        // the directory to upload to
        String uploadDir = getServletContext().getRealPath("/resources");

        // The following seems to happen when running jetty:run
        if (uploadDir == null) {
            uploadDir = new File("src/main/webapp/resources").getAbsolutePath();
        }
        //uploadDir += "/" + number + "/";
        return uploadDir;
    }

    private void copyAttachment(LoanRequest src, LoanRequest target) throws IOException {
        String srcUploadDir = getUploadPath();
        srcUploadDir += File.separator + src.getNumber();
        //File srcDirPath = new File(srcUploadDir);
        String targetUploadDir = getUploadPath();
        targetUploadDir += File.separator + target.getNumber();
        //File targetDirPath = new File(targetUploadDir);
        //FileUtils.copyDirectory(srcDirPath,targetDirPath);

        List<Attachment> list = src.getAttachmentList();
        List<Attachment> attachments = new ArrayList<Attachment>();
        for (Attachment attachment : list) {
            if (attachment.getType().equals(AttachmentType.Credit) || attachment.getType().equals(AttachmentType.Credit_Report) || attachment.getType().equals(AttachmentType.Request_Audit)) {
                Attachment newAtt = new Attachment();
                newAtt.setLoanRequest(target);
                newAtt.setName(attachment.getName());
                newAtt.setType(attachment.getType());
                newAtt.setTime(new Date());
                newAtt.setFileName(attachment.getFileName());
                newAtt.setOperator(attachment.getOperator());
                //attachmentManager.save(newAtt);
                attachments.add(newAtt);
                File srcDirPath = new File(srcUploadDir + File.separator + attachment.getName());
                File targetDirPath = new File(targetUploadDir + File.separator + attachment.getName());
                FileUtils.copyDirectory(srcDirPath, targetDirPath);
            }
        }
        target.getAttachmentList().clear();
        target.getAttachmentList().addAll(attachments);
    }
}
